#pragma once

// 公共数据结构

#include <time.h>
#include <string>

#include "logger.h"
#include "mjson.h"
#include "mjson_helper.h"
#include "json.hpp"

using json = nlohmann::json;

// 大部分 OJ 通用的错误码
#define OJ_WT0 0  // Pending
#define OJ_WT1 1  // Pending_Rejudging  TODO: 暂不实现重判功能
#define OJ_CI 2   // Compiling
#define OJ_RI 3   // Running_Judging
#define OJ_AC 4   // Accepted
#define OJ_PE 5   // Presentation Error
#define OJ_WA 6   // Wrong Answer
#define OJ_TL 7   // Time Limit Exceeded
#define OJ_ML 8   // Memory Limit Exceeded
#define OJ_OL 9   // Output Limit Exceeded
#define OJ_RE 10  // Runtime Error
#define OJ_CE 11  // Compilation Error
#define OJ_SE 12  // System Error
#define OJ_NT 13  // No Testdata

// 错误码到变量名的映射，方便 debug 用
std::map<int, std::string> oj_err_code_map = {{0, "Waiting Judge"}, {1, "Waiting Rejudge"}, {2, "Compiling"},  {3, "Running Judging"}, {4, "Accepted"},
                                              {5, "Presentation Error"},  {6, "Wrong Answer"},  {7, "Time Limit Exceeded"},  {8, "Memory Limit Exceeded"}, {9, "Output Limit Exceeded"},
                                              {10, "Runtime Error"}, {11, "Compilation Error"}, {12, "System Error"}, {13, "No Testdata"}};

struct MsgBuffer {
  long mtype;
  char mtext[1024];
};


// 这些结构体是从 backend 的 JSON RPC 部分人工翻译成 C++ 的
struct DispatchSolutionReq {
  int SolutionId;
  int ProblemId;
  // 为了防止代码里有奇怪字符影响 JSON 解码，所以传输前要对源代码做 base64 加密
  std::string SourceCode;
  int Language;
};

struct DispatchSolutionResp {
  bool Accept;
};

// 想不到怎么命名这种子结构体好，干脆统一在名字后加 msg 吧
struct JudgeStatusMsg {
  int RunnerId;  // 哪个 runner 负责
  int SolutionId;
  int ProblemId;
  int PassedTestCount;      // 当前评测到哪了
  int TotalTestCount;       // 测试点总数
  std::string JudgeResult;  // 最终评测结果
  bool IsJudgeOver;         // 评测完了吗？
  long LastUpdateTime;      // 最后更新时间，以此判断 judger 是否卡住
  int Language;             // 何种编程语言 @Language
};

struct QueryJudgeProcessReq {
  std::vector<int> SolutionId;
};

struct QueryJudgeProcessResp {
  int FreeJudgerNum;
  std::vector<JudgeStatusMsg> JudgeStatus;
};

// 所有 req 需要由 from_json，所有 resp 需要有 to_json

void from_json(const json& j, DispatchSolutionReq& req) {
  req.SolutionId = j.at("SolutionId").get<int>();
  req.ProblemId = j.at("ProblemId").get<int>();
  req.SourceCode = j.at("SourceCode").get<std::string>();
  req.Language = j.at("Language").get<int>();
}

void to_json(json& j, DispatchSolutionResp& resp) {
  j = json{
      {"Accept", resp.Accept},
  };
}

void from_json(const json& j, QueryJudgeProcessReq& req) {
  req.SolutionId = j.at("SolutionId").get<std::vector<int>>();
}

void to_json(json& j, const JudgeStatusMsg& msg) {
  j = json{{"RunnerId", msg.RunnerId},
           {"SolutionId", msg.SolutionId},
           {"ProblemId", msg.ProblemId},
           {"PassedTestCount", msg.PassedTestCount},
           {"TotalTestCount", msg.TotalTestCount},
           {"JudgeResult", msg.JudgeResult},
           {"IsJudgeOver", msg.IsJudgeOver},
           {"LastUpdateTime", msg.LastUpdateTime},
           {"Language", msg.Language}};
}

void from_json(const json& j, JudgeStatusMsg& msg) {
  msg.RunnerId = j.at("RunnerId").get<int>();
  msg.SolutionId = j.at("SolutionId").get<int>();
  msg.ProblemId = j.at("ProblemId").get<int>();
  msg.PassedTestCount = j.at("PassedTestCount").get<int>();
  msg.TotalTestCount = j.at("TotalTestCount").get<int>();
  msg.JudgeResult = j.at("JudgeResult").get<std::string>();
  msg.IsJudgeOver = j.at("IsJudgeOver").get<bool>();
  msg.LastUpdateTime = j.at("LastUpdateTime").get<long>();
}

void to_json(json& j, const QueryJudgeProcessResp& resp) {
  j = json{
      {"FreeJudgerNum", resp.FreeJudgerNum},
      {"JudgeStatus", resp.JudgeStatus},
  };
}
